//C- -------------------------------------------------------------------
//C- Java DjVu (r) (v. 0.8)
//C- Copyright (c) 2004-2005 LizardTech, Inc.  All Rights Reserved.
//C- Java DjVu is protected by U.S. Pat. No.C- 6,058,214 and patents
//C- pending.
//C-
//C- This software is subject to, and may be distributed under, the
//C- GNU General Public License, Version 2. The license should have
//C- accompanied the software or you may obtain a copy of the license
//C- from the Free Software Foundation at http://www.fsf.org .
//C-
//C- The computer code originally released by LizardTech under this
//C- license and unmodified by other parties is deemed "the LIZARDTECH
//C- ORIGINAL CODE."  Subject to any third party intellectual property
//C- claims, LizardTech grants recipient a worldwide, royalty-free,
//C- non-exclusive license to make, use, sell, or otherwise dispose of
//C- the LIZARDTECH ORIGINAL CODE or of programs derived from the
//C- LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
//C- General Public License.   This grant only confers the right to
//C- infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
//C- the extent such infringement is reasonably necessary to enable
//C- recipient to make, have made, practice, sell, or otherwise dispose
//C- of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
//C- any greater extent that may be necessary to utilize further
//C- modifications or combinations.
//C-
//C- The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
//C- OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
//C- TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
//C- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//C-
//C- In addition, as a special exception, LizardTech Inc. gives permission
//C- to link the code of this program with the proprietary Java
//C- implementation provided by Sun (or other vendors as well), and
//C- distribute linked combinations including the two. You must obey the
//C- GNU General Public License in all respects for all of the code used
//C- other than the proprietary Java implementation. If you modify this
//C- file, you may extend this exception to your version of the file, but
//C- you are not obligated to do so. If you do not wish to do so, delete
//C- this exception statement from your version.
//C- -------------------------------------------------------------------
//C- Developed by Bill C. Riemers, Foxtrot Technologies Inc. as work for
//C- hire under US copyright laws.
//C- -------------------------------------------------------------------
//
package com.lizardtech.djvu{
import java.io.*;
import java.util.*;


/**
 * DOCUMENT ME!
 *
 * @author $author$
 * @version $Revision: 1.10 $
 */
public final class GPixelReference
  extends GPixel
{
  //~ Instance fields --------------------------------------------------------

  private var parent:GMap;

  /** The current byte position in the data array. */
  private var offset:uint;
  
  private var ncolors:int;
  private var redOffset:int;
  private var greenOffset:int;
  private var blueOffset:int;

  //~ Constructors -----------------------------------------------------------

  /**
   * Creates a createGPixelReference object.
   *
   * @param parent the image map to refere to
   * @param offset the initial pixel position to refere to
   */

  // as3 overloading 
  public function GPixelReference(
    parent:GMap,
    row:int,
    column:*=null)
  {
  	if(column == null) {
  		GPixelReferenceA(parent, row);
  	} else {
  		GPixelReferenceB(parent, row, int(column));
  	}
  }   
   
  public function GPixelReferenceA(
    parent:GMap,
    offset:int)
  {
    this.parent   = parent;
    this.ncolors  = parent.getColorSize();
    this.offset   = offset * ncolors;
    blueOffset=parent.getBlueOffset();
    greenOffset=parent.getGreenOffset();
    redOffset=parent.getRedOffset();
  }

  /**
   * Creates a createGPixelReference object.
   *
   * @param parent DOCUMENT ME!
   * @param row DOCUMENT ME!
   * @param column DOCUMENT ME!
   */
  public function GPixelReferenceB(
    parent:GMap,
    row:int,
    column:int)
  {
    this.parent   = parent;
    this.ncolors  = parent.getColorSize();
    this.offset   = (parent.rowOffset(row) + column) * ncolors;
    blueOffset=parent.getBlueOffset();
    greenOffset=parent.getGreenOffset();
    redOffset=parent.getRedOffset();
  }

  //~ Methods ----------------------------------------------------------------

  /**
   * Copy the pixel values.
   *
   * @param ref pixel to copy
   */
  public final function setPixels(ref:GPixelReference,length:int):void{
    if(ref.ncolors != ncolors ||
            ref.blueOffset != blueOffset ||
            ref.greenOffset != greenOffset || 
            ref.redOffset != redOffset)
    {
      while(length-- > 0)
      {
        set(ref);
        ref.incOffset();
        incOffset();
      }
    }
    else
    {
      //System.arraycopy(ref.parent.data,ref.offset,parent.data,offset,length*ncolors);
      for(var sc:uint=0;sc<length*ncolors;sc++) {
      	parent.data[offset+sc] = ref.parent.data[ref.offset+sc];
      }
      ref.incOffset(length);
      incOffset(length);
    }
  }

  /**
   * Set the map image pixel we are refering to.
   *
   * @param offset pixel position
   */
  public function setOffset(a:*, b:*=null):void {
  	if(b == null) {
  		setOffset(int(a));
  	} else {
  		setOffsetB(int(a), int(b));
  	}
  }
   
  public function setOffsetA(offset:int):void{
    this.offset = offset * ncolors;
  }

  /**
   * Set the map image pixel we are refering to.
   *
   * @param row vertical position
   * @param column horizontal position
   */
  public function setOffsetB(
    row:int,
    column:int):void{
    this.offset = (parent.rowOffset(row) + column) * ncolors;
  }

  /**
   * Convert the following number of pixels from YCC to RGB. The offset will
   * be advanced to the end.
   *
   * @param count The number of pixels to convert.
   */
  public function YCC_to_RGB(count:int):void{
    if((ncolors != 3)||parent.isRampNeeded())
    {
        //throw new IllegalStateException("YCC_to_RGB only legal with three colors");
        throw new Error("YCC_to_RGB only legal with three colors");
    }
    while(count-- > 0)
    {
      var y:int= parent.data[offset];
      var b:int= parent.data[offset + 1];
      var r:int= parent.data[offset + 2];
      var t2:int= r + (r >> 1);
      var t3:int= (y + 128) - (b >> 2);
      var b0:int= t3 + (b << 1);
      parent.data[offset++] = int(((b0 < 255)
        ? ((b0 > 0)
        ? b0
        : 0)
        : 255));

      var g0:int= t3 - (t2 >> 1);
      parent.data[offset++] = int(((g0 < 255)
        ? ((g0 > 0)
        ? g0
        : 0)
        : 255));

      var r0:int= y + 128+ t2;
      parent.data[offset++] = int(((r0 < 255)
        ? ((r0 > 0)
        ? r0
        : 0)
        : 255));
    }
  }

  /**
   * Set the blue, green, and red values of the current pixel.
   *
   * @param blue pixel value
   * @param green pixel value
   * @param red pixel value
   */
  public override function setBGR(
    blue:int,
    green:int,
    red:int):void{
    parent.data[offset + blueOffset]  = int(blue);
    parent.data[offset + greenOffset] = int(green);
    parent.data[offset + redOffset]   = int(red);
  }

  /**
   * Set the blue pixel value.
   *
   * @param blue pixel value
   */
  public override function setBlue(blue:int):void{
    parent.data[offset+blueOffset] = blue;
  }

  /**
   * Query the blue pixel value.
   *
   * @return blue pixel value
   */
  public override function blueByte():int{
    return parent.data[offset+blueOffset];
  }

  /**
   * Create a duplicate of this GPixelReference.
   *
   * @return the newly created GPixelReference
   */
  public function duplicate():GPixelReference{
    return new GPixelReference(parent, offset);
  }

  /**
   * Fills an array of pixels from the specified values.
   *
   * @param x the x-coordinate of the upper-left corner of the region of
   *        pixels
   * @param y the y-coordinate of the upper-left corner of the region of
   *        pixels
   * @param w the width of the region of pixels
   * @param h the height of the region of pixels
   * @param pixels the array of pixels
   * @param off the offset into the pixel array
   * @param scansize the distance from one row of pixels to the next in the
   *        array
   */
  public function fillRGBPixels(
    x:int,
    y:int,
    w:int,
    h:int,
    pixels:Array,
    off:int,
    scansize:int):void{
    var yrev:int= parent.rows() - y;

    if(! parent.isRampNeeded())
    {
      for(var y0:int= yrev; y0-- > (yrev - h); off += scansize)
      {
        for(
          var i:int= off, j = (parent.rowOffset(y0) + x) * ncolors, k = w;
          k > 0;
          k--, j += ncolors)
        {
          pixels[i++] =
            0x000000| (0x0000& (parent.data[j + redOffset] << 16))
            | (0x00& (parent.data[j + greenOffset] << 8))
            | (0xff & parent.data[j + blueOffset]);
        }
      }
    }
    else
    {
      var ref:GPixelReference=parent.createGPixelReference(0);
      for(var y0:int= yrev; y0-- > (yrev - h); off += scansize)
      {
        ref.setOffset(y0,x);
        for(
          var i:int= off, k = w;
          k > 0;
          k--, ref.incOffset())
        {
          pixels[i++] = parent.ramp(ref).hashCode();
        }          
      }
    }
  }

  /**
   * Set the green pixel value.
   *
   * @param green pixel value
   */
  public override function setGreen(green:int):void{
    parent.data[offset + greenOffset] = green;
  }

  /**
   * Query the green pixel value.
   *
   * @return green pixel value
   */
  public override function greenByte():int{
    return parent.data[offset + greenOffset];
  }

  /**
   * Step to the next pixel.  Care should be taken when stepping past the end of a row.
   */
  //public function incOffset():void{
  //  this.offset += ncolors;
  //}

  /**
   * Skip past the specified number of pixels.  Care should be taken when stepping 
   * past the end of a row.
   *
   * @param offset number of pixels to step past.
   */
  public function incOffset(offset:int=1):void{
    this.offset += (ncolors * offset);
  }

  /**
   * Set the red pixel value.
   *
   * @param red pixel value
   */
  public override function setRed(red:int):void{
    parent.data[offset + redOffset] = red;
  }

  /**
   * Query the red pixel value.
   *
   * @return red pixel value
   */
  public override function redByte():int{
    return parent.data[offset + redOffset];
  }
  
  }
}